Skip to content

Security: claimBounty() permissionless DoS + agentDid spoofing#6

Open
philpof102-svg wants to merge 2 commits into
Gitlawb:mainfrom
philpof102-svg:fix-bounty-claim-dos
Open

Security: claimBounty() permissionless DoS + agentDid spoofing#6
philpof102-svg wants to merge 2 commits into
Gitlawb:mainfrom
philpof102-svg:fix-bounty-claim-dos

Conversation

@philpof102-svg

Copy link
Copy Markdown

Severity: HIGH (DoS), MEDIUM (reputation manipulation)

GitlawbBounty.claimBounty() has no caller verification. Two distinct issues :

  1. Indefinite DoS: anyone claims any bounty with arbitrary agentDid, does nothing, lets deadline pass, claims again after dispute — repeat forever. Creator's bounty locked indefinitely.

  2. agentDid spoofing: agentDid is unverified string. Earnings/completion stats attributed to arbitrary DID hash. Attacker credits victim or steals credit.

Full PoC + fix suggestions in BUG_REPORT_bounty_claim_dos.md.

Fix options (any one works) :

  • Bind agentDid to caller via GitlawbDIDRegistry.controllerOf()
  • Require minimum stake/tier
  • Require small refundable claim deposit (cheapest, most flexible)

Reporter @philpof102-svg — operator 0xAC3ca7c5d3cDD7702fd08F9C4C28dAA22296aDa9 on Base. Same reporter as PR #5.

@philpof102-svg

Copy link
Copy Markdown
Author

Urgent review requested — PR #6 and PR #7 are both HIGH severity. With 2 PRs in flight at high severity, the protocol surface is meaningfully exposed if either ships to mainnet.

I have a tested fix for #6 (DID Registry binding check) and 3 fix options for #7 (epoch checkpoints / pull-based / batched maintenance) in the bug reports. Happy to draft regression tests for both within 24h if confirmed wanted.

Open to coordinating disclosure timeline. Operator wallet on Base : 0xAC3ca7c5d3cDD7702fd08F9C4C28dAA22296aDa9

Adds an economic cost to claimBounty() — claimant must post a small
refundable deposit (1% of bounty amount, configurable up to 20%).
Refunded on submitBounty(), slashed to treasury on disputeBounty()
(claimant missed the deadline).

Closes the indefinite DoS where any address could claim any open
bounty for free, wait out the deadline, get disputed, and re-claim
in the same transaction, blocking the real solver forever.

- new storage: claimDepositBps (default 100 = 1%)
- new struct field: Bounty.claimDeposit
- claimBounty(): requires transferFrom(msg.sender, contract, deposit)
- submitBounty(): refunds deposit on success
- disputeBounty(): slashes deposit to treasury
- admin: setClaimDepositBps (capped at 2000 / 20%)
- event: ClaimDepositBpsUpdated

Backward compatible with bps=0 (existing behavior, no deposit required).

Related to PR Gitlawb#6 bug report.
@philpof102-svg

Copy link
Copy Markdown
Author

Upgraded this PR with a merge-ready Solidity fix in addition to the bug report.

Change (src/GitlawbBounty.sol, +41 lines):

  • New storage claimDepositBps (default 100 = 1%, configurable up to 20%)
  • New Bounty.claimDeposit struct field
  • claimBounty() requires transferFrom(claimant, contract, deposit)
  • submitBounty() refunds deposit on success
  • disputeBounty() slashes deposit to treasury (claimant missed deadline)
  • Admin: setClaimDepositBps(_bps) capped at 2000
  • Event: ClaimDepositBpsUpdated

Backward compatible — set claimDepositBps = 0 to preserve current behavior. Default 1% is small enough not to deter honest solvers and large enough that spam-claiming N bounties costs N × deposit upfront.

Happy to add tests or split into smaller PRs if you prefer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant